package org.agentsherpa.model;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Observable;

/**
 * Stores the Map with the Drone and IED coordinates
 * 
 * @author iain
 */
public class SimulatorModel extends Observable {
    private Map<Point, Drone> droneByLocation = new HashMap<Point, Drone>();
    private Map<String, Drone> droneByName = new HashMap<String, Drone>();
    private GlobalMap map;
    private Point startingPoint = new Point(0, 0);
    
    public SimulatorModel(GlobalMap map) {
        this.map = map;
    }

    public Drone addDrone(String name) {
        Point p = getStartingPoint();
        
        Drone d = new Drone(name, p);
        droneByLocation.put(d.getLocation(), d);
        droneByName.put(d.getName(), d);
        
        System.out.println("Adding drone " + d);
        
        setChanged();
        notifyObservers(d.getName());
        return d;
    }

    /**
     * Get the starting point for the agent.
     * 
     * @return
     */
    private Point getStartingPoint() {
        while (!isCellFree(startingPoint) || !map.isRoad(startingPoint)
                && startingPoint.getX() >= 0) {
            startingPoint = map.findNextRoad(startingPoint);
        }
        return startingPoint;
    }

    public boolean isCellFree(Point location) {
        if (droneByLocation.containsKey(location)) {            
            return false;
        }
        return true;
    }

    public Drone getDrone(String name) {
        return droneByName.get(name);
    }

    public void move(Drone drone, Direction direction) throws CollisionException {
        Point newLocation = direction.move(drone.getLocation());
        if (map.isRoad(newLocation)) {
            Point oldLocation = drone.getLocation();
            
            droneByLocation.remove(oldLocation);
            drone.setLocation(newLocation);
            droneByLocation.put(drone.getLocation(), drone);

            setChanged();
            notifyObservers(new DroneChange(oldLocation, drone));
        }
        else {
            throw new CollisionException(newLocation, drone);
        }
    }

    public GlobalMap getMap() {
        return map;
    }

    public Collection<Drone> getDrones() {
        return Collections.unmodifiableCollection(droneByName.values());
    }
    
    public static class DroneChange {
        private Point oldLocation;
        private Drone drone;

        DroneChange(Point oldLocation, Drone drone) {
            this.oldLocation = oldLocation;
            this.drone = drone;
        }

        public Drone getDrone() {
            return drone;
        }

        public Point getOldLocation() {
            return oldLocation;
        }
    }
}
